﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Composition;
using System.Composition.Hosting;
using System.Linq;
using System.Reflection;

using ServiceContainer = System.ComponentModel.Design.ServiceContainer;

namespace GaleSong
{
    public static class Global
    {
        #region Field

        private static readonly AppBootstrapper appBootstrapper = new AppBootstrapper();

        #endregion

        public static Action<object> Initalize = o => { appBootstrapper.Init(); };

        public static Action<object> Exit = o => { };

        public static Action<object> Load = o => { };
    }

    public class AppBootstrapper
    {
        #region Field

        private readonly ServiceContainer _serviceContainer = new ServiceContainer();
        private CompositionHost _compositionHost;

        #endregion

        #region Init

        public void Init()
        {
            IoC.GetInstance = GetInstance;
            IoC.GetAllInstances = GetAllInstances;
            IoC.AddInstance = AddService;
            IoC.BuildUp = BuildUp;
            Configure();
        }

        #endregion

        #region IoC

        private void AddBuildUp<T>(T serviceInstance)
        {
            AddService(serviceInstance);
            BuildUp(serviceInstance);
        }

        public void AddService(Type serviceType, object serviceInstance)
        {
            _serviceContainer.AddService(serviceType, serviceInstance);
        }

        public void AddService<T>(T serviceInstance)
        {
            _serviceContainer.AddService(typeof (T), serviceInstance);
        }

        private IEnumerable<Assembly> GetAddins()
        {
            // 1. 启动支持
            AssemblySource.Instance.Add(Assembly.GetEntryAssembly());
            //AssemblySource.Instance.Add(Assembly.LoadFile(Environment.CurrentDirectory + "\\" + "GaleSong.Foundation.dll"));

            // 2. 插件支持
            var catalog = new DirectoryCatalog(Environment.CurrentDirectory + "\\", "GaleSong.*.dll");
            AssemblySource.Instance.AddRange(catalog.LoadedFiles.Select(Assembly.LoadFile));

            return AssemblySource.Instance;
        }

        private void Configure()
        {
            var addins = GetAddins();
            _compositionHost = new ContainerConfiguration().WithAssemblies(addins).CreateContainer();

            AddBuildUp<IResourceService>(new ResourceService());
            AddBuildUp<IConfigurationService>(new ConfigurationService(""));
            AddBuildUp<IMainService>(new MainService());
        }

        private DirectoryCatalog CreateDirectoryCatalog(string path)
        {
            var catalog = new DirectoryCatalog(path, "GaleSong.*.dll");
            AssemblySource.Instance.AddRange(catalog.LoadedFiles.Select(Assembly.LoadFile));
            return catalog;
        }

        protected object GetInstance(Type serviceType, string key)
        {
            object instance = _serviceContainer.GetService(serviceType);
            if (instance != null)
            {
                return instance;
            }

            return null;
        }

        protected IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return null;
        }

        protected void BuildUp(object instance)
        {
            _compositionHost.SatisfyImports(instance);
        }

        #endregion
    }
}